package com.lifeng.zk.nativeapi;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * Created by lifeng on 2018/6/11.
 */
public class NodeOperateTest {
    private static String zkUrl = "127.0.0.1:2181";
    //连接超时时间
    private static Integer sessionOutTime = 5000;
    /** 信号量，阻塞程序执行，用于等待zookeeper连接成功，发送成功信号 */
    private static final CountDownLatch connectedSemaphore = new CountDownLatch(1);

    private static ZooKeeper zk;

    public static void main(String[] args) throws Exception {
        zk = new ZooKeeper(zkUrl, sessionOutTime, new Watcher() {
            public void process(WatchedEvent watchedEvent) {
                //获取事件的状态
                Event.KeeperState state = watchedEvent.getState();
                //获取事件类型
                Event.EventType type = watchedEvent.getType();
                //如果是建立连接
                if(Event.KeeperState.SyncConnected.equals(state)){
                    if(Event.EventType.None.equals(type)){//None 是连接
                        //如果建立连接成功，则发送信号量，让后续阻塞程序向下执行
                        connectedSemaphore.countDown();
                        System.out.println("zk 建立连接。。。");
                    }
                }
            }
        });
        connectedSemaphore.await();
        //createNode();
        //readData();
        //delNode();
        //existNode();
        //setData();
        //getChildrenNode("/test");
        //delNodes("/test");
        //createNode1();
        createNode2();
    }
    /** 创建节点*/
    public static void createNode1() throws Exception {
        zk.create("/test","test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);//节点临时
        Thread.sleep(10000);
    }
    /** 创建节点*/
    public static void createNode2() throws Exception {
        zk.create("/b","test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT_SEQUENTIAL);//节点临时
        zk.create("/a","test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT_SEQUENTIAL);//节点临时

        Thread.sleep(6000);
    }
    /** 创建节点*/
    public static void createNode() throws Exception {
        /***
         * 参数1，节点路径（名称）：/nodeName。不允许递归创建节点，在父节点不存在的情况下，不允许创建子节点。
         参数2，节点内容：要求类型是字节数组，也就是说不支持序列话方式，如果需要实现序列化，可使用java相关序列化框架，如Hessian，Kryo。
         参数3，节点权限：使用Ids.OPEN_ACL_UNSAFE开放权限即可。
         参数4，节点类型：创建节点的类型，CreateMode.*，提供了如下所示的四种节点类型：
         ①PERSISTENT（持久节点）
         ②PERSISTENT_SEQUENTIAL（持久顺序节点）
         ③EPHEMERAL（临时节点，本次会话有效）
         ④EPHEMERAL_SEQUENTIAL（临时顺序节点，本次会话有效）
         异步方式（在同步方法参数的基础上增加两个参数）：
         参数5，回调方法：注册一个异步回调方法，要实现AsynCallBack.StringCallBack接口，重写processResult(int rc, String path, Object ctx, String name)方法，当节点创建完成后执行此方法。
         ①rc：服务端响应码，0表示调用成功、-4表示端口连接、-110表示指定节点存在、-112表示会话已过期。
         ②path：接口调用时传入的数据节点的路径参数。
         ③ctx：调用接口传入的ctx值。
         ④name：实际在服务端创建的节点的名称。
         参数6，传递给回调方法的参数，一般为上下文（Context）信息。
         */
        //节点存在时创建会报错
        String node = zk.create("/test","测试".getBytes("UTF-8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("创建了"+node);

        String node1 = zk.create("/test/a","测试a".getBytes("UTF-8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("创建了"+node1);

    }

    /**读取数据*/
    public static void readData() throws Exception{
        //获取node数据
        byte[] data = zk.getData("/test/a",false,null);
        System.out.println("read data:/test," + new String(data,"UTF-8"));
    }

    /**删除*/
    public static void delNode() throws Exception{
        zk.delete("/test/a",-1);//第二个参数是版本
    }

    /**是否存在*/
    public static void existNode() throws Exception{
        Stat stat = zk.exists("/test",false);
        if(stat == null){
            System.out.println("节点不存在");
        }else{
            System.out.println(stat.toString());
        }
    }

    /**更新数据*/
    public static void setData() throws Exception{
        Stat stat = zk.setData("/test","test111".getBytes("UTF-8"),-1);
        System.out.println(stat);
    }
    /**递归获取所有子节点*/
    public static void getChildrenNode(String pnode) throws Exception {
        List<String> list = zk.getChildren(pnode,false);
        for(String node : list){
            System.out.println("children node:"+pnode+"/"+node+",data:"+new String(zk.getData(pnode+"/"+node,false,null)));
            getChildrenNode(pnode+"/"+node);
        }
    }

    /**递归删除节点*/
    public static void delNodes(String pnode) throws Exception{
        List<String> list = zk.getChildren(pnode,false);

        for (String node : list) {
            delNodes(pnode + "/" + node);
        }

        System.out.println("删除"+pnode);
        zk.delete(pnode,-1);
    }
}
